Search Results: "dburrows"

4 July 2008

Daniel Burrows: hello.cc

Daniel Burrows: CWidget tutoral 1: 'Hello, world!'

Late last year, I spent some time disentangling aptitude's internal UI library and packaging it as a separate library, which I named cwidget. This article is the first in what will hopefully become a series describing the basic concepts and APIs of cwidget. It applies to the versions of cwidget currently available in Debian sid and lenny, 0.5.11-1 and 0.5.12-1. Autogenerated documentation of cwidget can be found here (but beware that as of this writing it is somewhat incomplete).
In this tutorial, I will walk through a simple program (hello.cc) that initializes cwidget, displays a simple message box, and then terminates the program when the user confirms the message. I assume a basic familiarity with C++. Screenshot of the 'Hello, World' program The first thing to do is to include the portions of cwidget that our program will use. Most importantly, we need the top level cwidget routines. These are the global routines that initialize cwidget, shut it down, and control its main loop (among other things).
#include <cwidget/toplevel.h>
cwidget comes with a collection of stock dialog boxes for things like displaying messages to the user. To access the routines that build these dialogs, we write:
#include <cwidget/dialogs.h>
All the symbols provided by the cwidget library are in the cwidget namespace. Using the full library name means that there's a reasonable chance that its names will not conflict with the names provided by other libraries; however, it's a real pain to type cwidget over and over. Since this is the only namespaced library we are using in this program, it's handy to define cw as an alias for cwidget:
namespace cw = cwidget;
Now we're ready to write the main routine. The first interaction of client code with the cwidget library is to initialize it. This will initialize the ncurses library and put the terminal into a mode suitable for a full-screen curses program.
cw::toplevel::init();
Next, we create a dialog box that will be displayed to the user. There are two things to note about this code:
  1. cwidget is Unicode-aware and the ok() routine expects the message string to be a wide-character string. In this case, that means that we need to pass in a wide-character string (indicated by typing L in front of the string).
  2. The second argument tells cwidget what to do when the ok button is pressed. The expression
      sigc::ptr_fun(cw::toplevel::exitmain);
    
    creates a slot using libsigc++. Briefly, a slot is a reference to a function or to a method of a class instance. When invoked, this particular slot will call cwidget::toplevel::exitmain(), which causes the main cwidget loop to exit. The slot is wrapped in cwidget::util::arg, a utility function that handles passing slots as optional arguments.
cw::widgets::widget_ref dialog =
    cw::dialogs::ok(L"Hello, world!",
                    cw::util::arg(sigc::ptr_fun(cw::toplevel::exitmain)));
Now that we have a widget, the next step is to arrange for it to appear on the terminal. In cwidget, control of the terminal is assigned to a single top-level widget: whatever it displays is what gets displayed on the terminal, and all user input is passed directly to it. In a real program this widget will typically manage a collection of sub-widgets and assign each one a screen region, but for now let's just display the dialog box we created:
cw::toplevel::settoplevel(dialog);
With everything initialized, we're ready to start the main loop. mainloop() will keep the display up-to-date and dispatch incoming events (for instance, keystrokes and mouse presses) until exitmain() is invoked.
cw::toplevel::mainloop();
When the user presses Enter or clicks on the Ok button in the dialog, exitmain() will be invoked by the binding that we set up earlier. Once this happens, we need to shut down cwidget in order to restore the terminal to its original state. If you skip this step, the terminal will be garbled and will not work properly when your program exits.
cw::toplevel::shutdown();
And that's it! To compile the program, change to the directory containing hello.cc and run:
$ g++ -o hello hello.cc $(pkg-config --cflags --libs cwidget)
Of course, you'll need to have the g++ and libcwidget-dev packages installed for this to work!

23 June 2008

Obey Arthur Liu: Daniel Burrows on cwidget-gtk

Sometimes people propose other solutions to have the Aptitude-gtk project done, like :
I d have thought that the most interesting way of doing aptitude-gtk would be to write a gtk backend for libcwidget. -Karellen
As this might be of interest to more people, I’ll repost Daniel Burrows‘ response :
Although I can see where you re coming from, a GTK+ backend to cwidget would have no significant upsides and significant downsides. The main upside to doing that from a practical point of view is that you would have only one piece of driver code for the GTK+ and curses interfaces. You wouldn t have to rewrite the entire interface from scratch to create a GUI frontend. But this is just an illusory benefit. cwidget is a terminal interface library and aptitude s curses frontend is a terminal-based UI. From a practical point of view, this means that aptitude regularly assumes that, for instance, to clear out a line it s sufficient to output $WIDTH space characters (ASCII 32) with the desired background style. A port of cwidget to GTK+ would have to introduce new, interface-independent abstractions for all operations like this and eliminate all direct use of terminal-based assumptions, at a significant cost in complexity for both cwidget and the aptitude frontend. In order to transition to these new conventions, I believe you would have to rewrite large portions of both cwidget *and* aptitude in order to make the interface abstraction layer work. (remember: the justification for doing this is to avoid having to rewrite aptitude!) Furthermore, while this approach avoids reimplementing aptitude s curses interface (sort of, except where it doesn t see above), it does so at the cost of requiring you to reimplement all of cwidget, for GTK+. I just did a quick line count (with wc -l ): in all of cwidget there are 23,390 lines of code, while aptitude s curses frontend has around 23,359 lines of code (some of which are actually shared with the other frontends but are in the curses directory due to the historical organization of the code tree). Not only is a rewrite of cwidget more involved, but the amount of code you d have to replace is comparable to the amount implicated in a rewrite of aptitude itself! Finally, even if these costs weren t enough to eliminate the idea, it s not at all clear to me that a GTK+ backend for cwidget is even desirable. Although aptitude has some superficial similarities to a GUI program, the process of designing an interface to run in a terminal (where the available input mechanisms are relatively restricted and all output is to a character-cell grid) is rather different from the process of designing a GUI. GUI programs can t rely on some simplifying assumptions that terminal programs can, and at the same time they have a lot more options available to them (just to name a few: graphics, multiple windows, differing text sizes and rotated text). Trying to force everything through an abstraction designed for terminal output would require you to either
  1. eschew those options,
  2. provide abstract GUI components that somehow fell back to terminal rendering in a terminal, or
  3. add ways for the frontend to extend the abstract widgets with custom functionality.
1. is not an option because I (and, I think, Arthur) want to design a good GTK+ package manager, not a good GTK+ imitation of a console package manager. 2. and 3. amount, in my strong opinion, to writing two separate interfaces but intertwining their implementations in a mass of maintenance-resistant and extension-resistant spaghetti code. At the end of the day, I think that having two separate frontends (sharing backend logic where appropriate, of course) is a far cleaner and more maintainable design, and also easier to create.
As I said earlier, I intend to go a little farther than just making a GTK+ “skin” over the curses interface. Think less like gvim and emacs and more like maybe ddd. I should also add that the cwidget library is used by no major programs except Aptitude so few others would benefit from a GTK+ backend. As the cwidget library homepage says:
cwidget was originally an internal user interface library for the aptitude package manager. This means, on the one hand, that cwidget is known to work in the real world for a real application; on the other hand, it means that the feature set of cwidget is coextensive with the requirements of aptitude.

19 June 2008

Daniel Burrows: Welcome to Obey Arthur Liu, GSOC coder

So I've been inexcusably tardy in announcing this, but Obey Arthur Liu is working on aptitude for Google's Summer of Code program. His goal is to write a third interface to the program, using GTK+ to produce the UI; as the abstract for his project states:
I will create a GTK+ GUI for Aptitude that will work alongside improved current ncurses and command-line interfaces. This will offer an alternative to Synaptic with an interface design geared toward usability and advanced functionality.
I'm looking forward to seeing what he comes up with! I think there are a lot of interesting possibilities in the design space of GUI package managers; hopefully he'll have time to explore at least a few of them. At the moment he's focusing on figuring out the care and feeding of the apt library backend and learning some of the quirks you have to deal with when writing a frontend against it. Arthur's blog can be found at http://www.milliways.fr and on Planet Debian. The Mercurial repository for his work can currently be found at http://dev.graffit.net/aptitude/hg/.

7 June 2008

Daniel Burrows: aptitude 0.4.11.4 released

I've released version 0.4.11.4 of the aptitude package manager (release notes). The main motivation for this release is bug #483920, which would cause the resolver to choose solutions badly (e.g., it might prefer downgrading a bunch of packages to keeping them at their current versions). It also includes a simple fix for bug #136874, the fact that the output of aptitude search is badly suited for scripts (it still is, but now there's a command-line option that will make it better).

15 May 2008

Daniel Burrows: Worst Debian day ever.

Regarding the OpenSSL debacle, Julien Blache writes:
Worst Debian day ever since the 2003 compromise. And that was a BAD one.
I disagree. This is far, far worse than the 2003 compromise. The compromise was scary, but the key updates for users were straightforward and as far as we know, user security was never actually compromised. In contrast, every single user who uses Debian or Ubuntu for anything serious is now (Update: and has been for two years) vulnerable to attacks on their supposedly secure cryptography [0] unless they perform a labor-intensive and error-prone series of steps to regenerate all their cryptographic keys -- not to mention finding a secure way to distribute their public keys to everyone who needs them! [0]: Update: I should perhaps make it clear that I mean anyone who generated a key on such a system. But in a way this makes things worse: unless you're willing to regenerate every key in sight, you need to check each key manually, which means that there's a nontrivial chance that you'll overlook one and leave yourself vulnerable...

14 May 2008

Julien Blache: Of course it s far worse. Did I tell otherwise?

Dear Daniel, It looks like you are referring to my post, though you got my name wrong so that wasn’t immediately obvious. Of course this is far worse than the 2003 compromise in terms of the direct, known and quantifiable impact it has on our users. I don’t think I stated otherwise, so I hardly see why your post starts with “I disagree”.

9 May 2008

Daniel Burrows: Breaking radio silence

We've spent the last week and a half moving out of the bizarre twilight zone known as Redmond into the city of Seattle proper. This cuts down on my commute tremendously (although poor Kate has to do the opposite of what I used to do each day), and it's great to be able to walk to the grocery store whenever I want. It may also mean that I'll cut back a bit on my Debian work in favor of actually having a life. Half my stuff is still in boxes, so I'll be busy with this move for a while longer, but at least I have Internet and email access again now.

21 April 2008

Daniel Burrows: The trifecta of loathing

I talked to my mother last week about the upcoming Pennsylvania primary (scheduled for tomorrow, April 22nd). She lives in the semi-rural Pennsylvania town where I grew up, and so I asked her what her impression was of how the locals felt about the campaign. Well, she said, they think the war is a disaster and they don't want to vote for McCain because they think he'll continue it forever. And of course they don't want to vote for a black man. And they all hate Hillary and think she's evil. So they're having some trouble trying to decide who to vote for; they can't figure out which candidate they despise the least.

12 April 2008

Daniel Burrows: aptitude 0.4.11.2 released

I've released version 0.4.11.2 of the aptitude package manager (release notes). This is basically a bugfix release to clean out some problems that were introduced in the previous release (most notably a nasty problem in safe-upgrade).

5 April 2008

Daniel Burrows: aptitude 0.4.11.1 released

Last weekend, I released version 0.4.11.1 of the aptitude package manager (release notes). This is a minor release focusing mostly on bug-fixes and on a few features that I've been meaning to add but that didn't make it into 0.4.11. I think the most interesting addition is --show-why, which is like --show-deps but traces back to the closest manually installed package. In some wide-character locales, the fix for bug #472625 in this upload of aptitude triggers bug #473874 and bug #474065 in apt; the symptoms are an error message about line N too long (max 1024) on start-up, and messages saying that method http has died unexpectedly! when you try to update the package lists or install new packages. I've written patches to fix these bugs in apt, and once they're reviewed by the other apt maintainers they should be fixed in the next upload of apt (version 0.7.12). Until then, if you're bitten by this bug, you can work around it by diverting /usr/share/aptitude/aptitude-defaults.$LANG and replacing it with an empty file. For instance, for Russian (ru):
 # dpkg-divert --rename --local --divert /usr/share/aptitude/aptitude-defaults.ru.real --add /usr/share/aptitude/aptitude-defaults.ru
 # echo > /usr/share/aptitude/aptitude-defaults.ru
Once a fixed apt is uploaded, you can remove the diversion like this:
 # rm /usr/share/aptitude/aptitude-defaults.ru
 # dpkg-divert --rename --local --remove /usr/share/aptitude/aptitude-defaults.ru

16 March 2008

Joey Hess: re: Apologies for spamming the planet...

Daniel, there have never, ever, been any changes in ikiwiki can could result in GUID changes on upgrade, with the exception of enabling usedirs, which is something you have to do manually. And there never will be any if I have anything to say about it.. Of course, you can cause the GUIDs of posts to change by renaming or moving the files around, or by changing the url to your blog. Doesn't explain why it happened of course.. PS, can I git clone your blog from somewhere? There's an interesting blip in your RecentChanges page that I'd like to figure out, where one time the change author is listed as "Daniel Burrows Daniel_Burrows".

Daniel Burrows: Apologies for spamming the planet...

I just happened to take a look at the output of a Web log analyzer and noticed a huge increase in traffic yesterday. I thought that was odd, since I hadn't written any new blog posts recently or published new stuff on my Web page. So I took a look at the logs themselves and noticed that a whole bunch of my recent hits listed their referer as planet.debian.net. This is where you start getting a sinking feeling...and yes, when I checked the Planet in a Web browser, sure enough, it looks like my whole blog got dumped out on the Planet. For some reason my own RSS reader didn't pick it up, so I wouldn't even have noticed if I hadn't been checking on my Web server stats. I'm not sure why, but I bet it has to do with the fact that I upgraded ikiwiki yesterday. So if you've seen the new ikiwiki version that came out recently, take a little care when you update and make sure it doesn't impact your RSS feed.

Daniel Burrows: 'Suck less' mugs on Cafepress

On the Seattle Underground tour, they tell you about Seattle spirit, which boils down to:
If you've got a bad idea, stick with it!
A while back, I posted about how I had created a T-shirt with a cute little graph showing the decrease in Suck over time. I have yet to sell a single one, but I've had a similar graphic pinned up in my cubicle at work for a while, and several people there have told me they think it should go on a coffee mug. So what the heck, I spent some time today resizing the picture, and now you can get it on a mug, large mug, or stein.

Daniel Burrows: aptitude 0.4.11 released

I've released version 0.4.11 of the aptitude package manager (release notes). Due to ongoing work by the installer team, I uploaded this release to experimental rather than unstable; once things are clear I will upload a build to unstable (probably promoting the experimental cwidget to unstable at the same time). The initial upload accidentally left out libept support, so I'm preparing a new upload as I write this. The aptitude search language and its documentation have gotten particular attention in this release. The most visible change is the introduction of a new syntax for search expressions: in addition to the old style of ~i, you can now type ?installed. Not only is this more readable and more memorable, it means that I'll be much more able to expand the breadth of the query language: it was becoming rather difficult to select new single-character flags for search terms, so expanding the namespace is nice. On this note, a number of search terms have been added to the language; see the release notes or the aptitude user's manual for details.
PS: if you're wondering about the quote in the release notes: I just needed to vent a little about that incident in a way that I found amusing and harmless; I'm over it now, and hopefully this will be the last time I mention it in public.

15 March 2008

Daniel Burrows: Installing packages in safe-upgrade

Colin Watson writes:
I do sometimes wonder why we don't relax the definition of "safe" upgrades to include installing new packages but still not removing old ones. I know that many of my uses of dist-upgrade are just for when something grows a new dependency that I didn't previously have installed.
That's a good question. Like many things in aptitude, the basic design was copied from apt-get, and I haven't thought much about it since then. But in fact, I think this makes a lot of sense, and it turns out that it's fairly easy to acheive. I've just checked a change into head that makes safe-upgrade allow new packages to be installed. This is accomplished using aptitude's dependency resolver, restricted to only consider holding packages back or installing the candidate version of a package (that is, the version that aptitude install would choose by default). If the resolver produces a solution, it's applied blindly; otherwise we fall back to the current behavior (and probably fail). The current behavior is still available through aptitude --no-new-installs safe-upgrade and the configuration option Aptitude::CmdLine::Safe-Upgrade::No-New-Installs. The one thing that might get missed are broken recommendations -- libapt doesn't consider these to be broken dependencies, so aptitude won't notice them unless there are broken real dependencies. These will get fixed in full-upgrade because it uses apt's resolve trivial dependencies algorithm. That's probably what's doing the wrong thing with conflicts, but it also has logic to do the right thing with new recommendations. Regardless, those wouldn't have been fixed by the old logic of safe-upgrade, so this is not a regression.

Daniel Burrows: Full upgrade and conflicts

Erich Schubert wonders how to improve the handling of conflicts in package managers, particularly in aptitude full-upgrade and apt-get dist-upgrade. From the point of view of the package manager, conflicts are a bit tricky to deal with. The problem is that a conflict only really tells you not to install two packages at once; it doesn't tell you which package should end up on the system by default. Worse, aptitude has two approaches to this:
  • When a package is marked for installation in the visual interface or listed on the command-line, then if Aptitude::Auto-Install is enabled, aptitude will automatically resolve conflicts in favor of that package. The same applies to packages that are upgraded by pressing U or by full-upgrade.
  • When aptitude's dependency resolver encounters a conflict, it considers both resolutions to the conflict to be equally valid. If there are no other reasons to choose one package over the other, it will be unpredictable which one gets removed first, and even when there are reasons to choose, the user may not understand what they are.
I don't think it's possible to always make upgrades predictable. But I think that even just making Auto-Install stick to installing packages and not removing conflicts would be a plus. Installing obvious dependencies up-front is good because it means less work for the resolver and a more predictable starting point. Many trivial dependency problems can even be completely solved this way. But removing conflicts is a lot trickier and should probably kick the problem into the full resolver. Unfortunately, the code enabled by Auto-Install is all deep in the guts of libapt. I've tried to avoid duplicating this code so far, but it does seem like I periodically run into cases where it doesn't do exactly what I need, so maybe I'll have to eventually. :-(

Daniel Burrows: Suck less T-shirts on Cafepress

A few months ago I made up a chart at work showing our development team's goal. It was popular enough around the office that I decided to make a similarly themed design in my spare time and sell it on Cafepress. The chart looks like this: suckless-graph-thumbnail.png This is available in the usual assortment of T-shirts, as well as a few other items. If you'd like an item that's not listed (say, a coffee mug), please email me and I'll add it to the store.

Daniel Burrows: HOWTO get and compile the apt source repository using bzr

Getting apt apt's source code is managed using bzr. Very fine tutorials and documentation on bzr exist on the Web; I'll give a brief rundown of some useful commands here, but you should read bzr-specific documentation to get a complete understanding of it. bzr is available in the Debian repositories, and likely other distributions have a package of it as well. The master apt branch for Debian is available at http://bzr.debian.org/apt/debian-sid. Yes, that looks like an empty directory if you view it with a Web browser, but it really contains the source tree. To retrieve it, run:
bzr branch http://bzr.debian.org/apt/debian-sid apt-debian-sid
That will download the repository to the directory apt-debian-sid. It takes a long time to download a fresh copy of the code, so be patient. When bzr branch finishes running, you have a new private copy of the source tree to work with. You can commit changes with bzr commit, download updates with bzr merge, see what you've changed with bzr diff, and copy your changes to a public location with bzr push. Read the bzr manpage and user's manual for full documentation on how to use bzr. Other public repositories of apt code include:
Compiling apt from its repository To compile apt, you'll need the following packages on Debian:
  • g++
  • make
  • libdb4.4-dev
  • gettext
  • libcurl4-gnutls-dev or libcurl3-gnutls-dev
  • xmlto
That will allow you to build apt without installing it by running make. xmlto is not listed in the Build-Depends line of apt, but you won't be able to produce manpages without it. In particular, you'll need it to produce a Debian package (see below).
Installing a build of the apt repository The easiest way to install a custom build of apt out of a repository checkout is to build a Debian package from the checkout. Install the following packages:
  • dpkg-dev
  • debhelper
and run the following command in the top-level directory of the apt repository:
dpkg-buildpackage -rfakeroot -us -uc
This will compile apt and produce several .deb packages in the parent directory of the repository. To install the generated packages, I recommend first installing the devscripts package and then running debi. You can also install the .deb packages by hand by running dpkg -i FILENAME.deb (...). Warning: installing an interim build of apt is likely to break all the packages that depend on it, such as aptitude and synaptic; interim builds might also be buggy and do strange things to your system. You should not install an unreleased version of apt unless you are sure that you can fix any problems that you encounter as a result of doing so.

Daniel Burrows: HOWTO convert your Blogger/BlogSpot blog to ikiwiki

Until recently, my blog was hosted on Google's free Blogger service. When I decided to move to my own server and ikiwiki, I didn't want to lose all my old posts. But exporting your blog from Blogger is a bit tricky. In fact, the Blogger page that provides instructions on how to do so starts off by saying:
Blogger does not have an export or download function.
Regardless of what they say, you can cajole Blogger into exporting text for use in other blog systems. Instructions for moving from Blogger to various pieces of software are available out there on the Web, but to switch to ikiwiki I had to tweak them a bit. Here's the procedure I used:
  1. Extract your information from Blogger's clutches and add minimal IkiWiki tags. As in the official Blogger instructions, change your template temporarily. However, instead of using the page template they suggest, use the following template, which you can find as a text file here.
    <Blogger>
    [[meta author="<$BlogItemAuthor$>"]]
    [[meta date="<$BlogItemDateTime$>"]]
    [[meta title="<$BlogItemSubject$>"]]
    <$BlogItemBody$>
    </Blogger>
    <BlogItemComments>
    Comment by <$BlogCommentAuthor$> at <$BlogCommentDateTime$>:
    <$BlogCommentBody$>
    </BlogItemComments>
    
    I recommend saving the file that's produced by this step even after you process it in the next step, in case you discover that you made a mistake.
  2. Split the extracted file into pieces. Exporting your blog using the template above will get you all your blog posts in reasonable Markdown format, with all dates and titles preserved. But they'll all be scrunched into one file. Blogspot also won't interpret paragraph breaks into blank lines, and it inserts strange empty <div> tags all over. So the next step is to split this file into pieces and clean up the HTML. Since I had over a hundred posts, I wrote a Python script to do this postprocessing for me. You can find it here. You can run it like this to output each blog post as a separate file in the current directory:
    /path/to/fixup-blogspot-export input-file
    
    This script makes a few assumptions about its input file:
    1. It assumes that the text [[meta author="NAME']] does not appear at the start of a line anywhere except the first line of a blog post. If you write about MarkDown syntax on your blog, you will run into problems.
    2. It makes a similar assumption about Ikiwiki's date meta.
    3. It assumes that line breaks are expressed using a variant of <br/>, and that <br/> never appears in the text of your blog.
    4. It assumes that the text Comment by does not appear at the start of a line in any post.
    5. It assumes, in general, that no Markdown or Ikiwiki commands appear in the blog text. If any do, you'll have to manually escape them, either before or after running the conversion script.
    All in all, it's probably a good idea to at least skim the output once.
  3. Create a top-level Ikiwiki page for your blog. The Ikiwiki site has instructions on doing this that are probably better than I could write. The most important thing is to use the created-after tag to limit your RSS feeds, so you don't spew new posts all over the planet (pun intended). For instance:
     [[inline pages="./blog/entry/*"
              feedpages="created_after(last_page_of_the_old_blog)"]]
    

Next.

Previous.